<template>
  <div class="min-h-screen py-8 px-4 sm:px-6 lg:px-8">
    <div class="max-w-6xl mx-auto">
      <!-- 页面标题 -->
      <div class="text-center mb-12">
        <h1 class="text-4xl font-bold mb-4 tech-text">Media Source Extensions API</h1>
        <p class="text-gray-300 text-lg">
          动态构建媒体流，实现自适应流媒体和视频拼接功能
        </p>
      </div>

      <!-- 浏览器支持提示 -->
      <div v-if="!isSupported" class="tech-card mb-8 border-yellow-600">
        <div class="flex items-center mb-4">
          <i class="i-carbon-warning text-yellow-500 text-xl mr-3"></i>
          <h3 class="text-xl font-semibold text-yellow-500">浏览器支持提示</h3>
        </div>
        <p class="text-gray-300">
          您的浏览器不支持 Media Source Extensions API。此功能需要现代浏览器支持。
        </p>
      </div>

      <!-- 视频播放器 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">MSE 视频播放器</h2>
        
        <div class="bg-gray-800 rounded-lg overflow-hidden mb-6">
          <video
            ref="videoRef"
            controls
            class="w-full"
            @timeupdate="handleTimeUpdate"
            @play="handlePlay"
            @pause="handlePause"
          ></video>
        </div>

        <!-- 控制按钮 -->
        <div class="flex flex-wrap gap-3 mb-6">
          <button
            @click="loadVideo"
            :disabled="isLoading || !isSupported"
            class="tech-button disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="i-carbon-play-filled mr-2"></i>
            {{ isLoading ? '加载中...' : '加载视频' }}
          </button>

          <button
            @click="appendSegment"
            :disabled="!mediaSource || sourceBuffer === null || isAppending"
            class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="i-carbon-add mr-2"></i>
            {{ isAppending ? '添加中...' : '添加片段' }}
          </button>

          <button
            @click="clearBuffer"
            :disabled="!sourceBuffer || isClearing"
            class="bg-orange-600 hover:bg-orange-700 text-white px-6 py-3 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="i-carbon-clean mr-2"></i>
            清空缓冲
          </button>

          <button
            @click="endStream"
            :disabled="!mediaSource || mediaSource.readyState !== 'open'"
            class="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="i-carbon-stop-filled mr-2"></i>
            结束流
          </button>
        </div>

        <!-- 状态信息 -->
        <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">MediaSource 状态</div>
            <div class="text-white font-semibold">
              {{ mediaSourceState || '-' }}
            </div>
          </div>

          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">SourceBuffer 状态</div>
            <div class="text-white font-semibold">
              {{ sourceBufferState || '-' }}
            </div>
          </div>

          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">已加载片段</div>
            <div class="text-white font-semibold">
              {{ segmentCount }}
            </div>
          </div>

          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">当前时间</div>
            <div class="text-white font-semibold">
              {{ currentTime.toFixed(2) }}s
            </div>
          </div>
        </div>
      </div>

      <!-- 缓冲区信息 -->
      <div v-if="sourceBuffer" class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">缓冲区信息</h2>
        
        <div class="space-y-4">
          <!-- 时间范围 -->
          <div>
            <h3 class="text-white font-medium mb-3">已缓冲时间范围</h3>
            <div v-if="bufferedRanges.length > 0" class="space-y-2">
              <div
                v-for="(range, index) in bufferedRanges"
                :key="index"
                class="bg-gray-800 rounded-lg p-3 flex justify-between items-center"
              >
                <span class="text-gray-300">范围 {{ index + 1 }}</span>
                <span class="text-white font-semibold">
                  {{ range.start.toFixed(2) }}s - {{ range.end.toFixed(2) }}s
                  <span class="text-gray-400 text-sm ml-2">
                    ({{ (range.end - range.start).toFixed(2) }}s)
                  </span>
                </span>
              </div>
            </div>
            <div v-else class="text-gray-400 text-center py-4">
              暂无缓冲数据
            </div>
          </div>

          <!-- 可视化进度条 -->
          <div>
            <h3 class="text-white font-medium mb-3">缓冲可视化</h3>
            <div class="relative h-12 bg-gray-800 rounded-lg overflow-hidden">
              <!-- 缓冲区域 -->
              <div
                v-for="(range, index) in bufferedRanges"
                :key="index"
                class="absolute h-full bg-tech-accent opacity-50"
                :style="{
                  left: `${(range.start / duration) * 100}%`,
                  width: `${((range.end - range.start) / duration) * 100}%`
                }"
              ></div>
              <!-- 播放位置 -->
              <div
                class="absolute h-full w-1 bg-white"
                :style="{ left: `${(currentTime / duration) * 100}%` }"
              ></div>
            </div>
            <div class="flex justify-between text-xs text-gray-400 mt-1">
              <span>0s</span>
              <span>{{ duration.toFixed(1) }}s</span>
            </div>
          </div>

          <!-- SourceBuffer 属性 -->
          <div class="bg-gray-800 rounded-lg p-4">
            <h3 class="text-white font-medium mb-3">SourceBuffer 属性</h3>
            <div class="grid grid-cols-2 gap-3 text-sm">
              <div>
                <span class="text-gray-400">Mode:</span>
                <span class="text-white ml-2">{{ sourceBuffer.mode }}</span>
              </div>
              <div>
                <span class="text-gray-400">Updating:</span>
                <span class="text-white ml-2">{{ sourceBuffer.updating }}</span>
              </div>
              <div>
                <span class="text-gray-400">Timestamp Offset:</span>
                <span class="text-white ml-2">{{ sourceBuffer.timestampOffset }}</span>
              </div>
              <div>
                <span class="text-gray-400">Append Window Start:</span>
                <span class="text-white ml-2">{{ sourceBuffer.appendWindowStart }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 事件日志 -->
      <div v-if="logs.length > 0" class="tech-card mb-8">
        <div class="flex justify-between items-center mb-6">
          <h2 class="text-2xl font-semibold text-white">事件日志</h2>
          <button
            @click="clearLogs"
            class="text-red-400 hover:text-red-300 text-sm"
          >
            <i class="i-carbon-clean mr-1"></i>
            清空日志
          </button>
        </div>

        <div class="space-y-2 max-h-64 overflow-y-auto">
          <div
            v-for="(log, index) in logs.slice().reverse()"
            :key="index"
            class="bg-gray-800 rounded-lg p-3 flex items-start text-sm"
          >
            <i
              :class="getLogIcon(log.type)"
              class="text-lg mr-3 mt-0.5"
            ></i>
            <div class="flex-1">
              <div class="text-white">{{ log.message }}</div>
              <div class="text-gray-400 text-xs mt-1">{{ log.timestamp }}</div>
            </div>
          </div>
        </div>
      </div>

      <!-- 模拟片段生成 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">模拟片段生成</h2>
        <p class="text-gray-300 mb-4">
          这个演示使用模拟数据展示 MSE 的工作原理。在实际应用中，片段数据通常来自服务器。
        </p>
        
        <div class="bg-gray-800 rounded-lg p-4">
          <h3 class="text-white font-medium mb-3">典型工作流程</h3>
          <ol class="list-decimal list-inside space-y-2 text-gray-300 text-sm">
            <li>创建 MediaSource 对象</li>
            <li>将 MediaSource 附加到 video 元素</li>
            <li>等待 sourceopen 事件</li>
            <li>创建 SourceBuffer</li>
            <li>从服务器获取媒体片段</li>
            <li>使用 appendBuffer() 添加片段数据</li>
            <li>等待 updateend 事件</li>
            <li>重复步骤 5-7 直到所有片段加载完成</li>
            <li>调用 endOfStream() 结束流</li>
          </ol>
        </div>
      </div>

      <!-- API 信息 -->
      <div class="tech-card">
        <h3 class="text-xl font-semibold mb-4 text-white">API 信息</h3>
        <div class="space-y-4 text-gray-300">
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">浏览器支持</h4>
            <p>Chrome 23+, Firefox 42+, Safari 8+, Edge 12+</p>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">主要接口</h4>
            <ul class="list-disc list-inside space-y-1">
              <li><code class="bg-gray-800 px-2 py-1 rounded">MediaSource</code> - 媒体源对象</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">SourceBuffer</code> - 源缓冲区对象</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">appendBuffer()</code> - 添加媒体片段</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">remove()</code> - 移除缓冲区数据</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">endOfStream()</code> - 标记流结束</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">关键事件</h4>
            <ul class="list-disc list-inside space-y-1">
              <li><code class="bg-gray-800 px-2 py-1 rounded">sourceopen</code> - MediaSource 准备就绪</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">sourceended</code> - MediaSource 已结束</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">sourceclose</code> - MediaSource 已关闭</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">updatestart</code> - 开始更新缓冲区</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">updateend</code> - 完成更新缓冲区</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">error</code> - 发生错误</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">使用场景</h4>
            <ul class="list-disc list-inside space-y-1">
              <li>自适应流媒体播放（DASH, HLS）</li>
              <li>视频点播和直播服务</li>
              <li>无缝视频拼接和切换</li>
              <li>客户端视频编辑</li>
              <li>广告插入和替换</li>
              <li>离线视频播放</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">支持的格式</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li>WebM (VP8/VP9/AV1 视频 + Opus/Vorbis 音频)</li>
              <li>MP4 (H.264/H.265 视频 + AAC 音频)</li>
              <li>格式支持取决于浏览器和平台</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">最佳实践</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li>始终检查 <code class="bg-gray-800 px-1 rounded">MediaSource.isTypeSupported()</code></li>
              <li>监听 SourceBuffer 的 updating 状态，避免并发更新</li>
              <li>合理管理缓冲区大小，及时清理旧数据</li>
              <li>处理所有错误事件，提供降级方案</li>
              <li>使用合适的片段大小（通常 2-10 秒）</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">与其他技术的关系</h4>
            <p class="text-sm leading-relaxed">
              MSE 通常与 <strong>DASH</strong>（Dynamic Adaptive Streaming over HTTP）或 
              <strong>HLS</strong>（HTTP Live Streaming）协议一起使用。
              这些协议定义了如何将媒体分割成片段并通过 HTTP 传输，
              而 MSE 提供了浏览器端组装和播放这些片段的能力。
              流行的库如 <strong>dash.js</strong>、<strong>hls.js</strong> 和 
              <strong>shaka-player</strong> 都基于 MSE 实现。
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onUnmounted } from 'vue'

// 类型定义
interface Log {
  type: 'info' | 'success' | 'warning' | 'error'
  message: string
  timestamp: string
}

interface BufferedRange {
  start: number
  end: number
}

// 响应式状态
const isSupported = ref('MediaSource' in window)
const isLoading = ref(false)
const isAppending = ref(false)
const isClearing = ref(false)

const videoRef = ref<HTMLVideoElement | null>(null)
const mediaSource = ref<MediaSource | null>(null)
const sourceBuffer = ref<SourceBuffer | null>(null)
const segmentCount = ref(0)
const currentTime = ref(0)
const duration = ref(0)

const logs = ref<Log[]>([])
const bufferedRanges = ref<BufferedRange[]>([])

// 计算属性
const mediaSourceState = computed(() => mediaSource.value?.readyState || null)
const sourceBufferState = computed(() => {
  if (!sourceBuffer.value) return null
  return sourceBuffer.value.updating ? 'updating' : 'ready'
})

// 添加日志
const addLog = (type: 'info' | 'success' | 'warning' | 'error', message: string) => {
  logs.value.push({
    type,
    message,
    timestamp: new Date().toLocaleTimeString('zh-CN')
  })
  
  // 只保留最近 50 条
  if (logs.value.length > 50) {
    logs.value.shift()
  }
}

// 获取日志图标
const getLogIcon = (type: string) => {
  const icons = {
    info: 'i-carbon-information-filled text-blue-400',
    success: 'i-carbon-checkmark-filled text-green-400',
    warning: 'i-carbon-warning-filled text-yellow-400',
    error: 'i-carbon-error-filled text-red-400'
  }
  return icons[type as keyof typeof icons]
}

// 清空日志
const clearLogs = () => {
  logs.value = []
}

// 更新缓冲区信息
const updateBufferedRanges = () => {
  if (!videoRef.value) return
  
  const buffered = videoRef.value.buffered
  const ranges: BufferedRange[] = []
  
  for (let i = 0; i < buffered.length; i++) {
    ranges.push({
      start: buffered.start(i),
      end: buffered.end(i)
    })
  }
  
  bufferedRanges.value = ranges
}

// 生成模拟视频数据（使用 canvas）
const generateVideoSegment = (_segmentIndex: number): Uint8Array => {
  // 注意：这里返回模拟数据
  // 实际应用中应该从服务器获取真实的媒体片段
  addLog('warning', '这是模拟数据。实际应用需要从服务器获取真实的媒体片段。')
  
  // 返回一个简单的模拟 WebM 头部（实际不可用于播放）
  return new Uint8Array([
    0x1a, 0x45, 0xdf, 0xa3, 0x9f, 0x42, 0x86, 0x81,
    0x01, 0x42, 0xf7, 0x81, 0x01, 0x42, 0xf2, 0x81
  ])
}

// 加载视频
const loadVideo = async () => {
  if (!videoRef.value || !isSupported.value) return
  
  isLoading.value = true
  addLog('info', '开始初始化 MediaSource...')
  
  try {
    // 创建 MediaSource
    mediaSource.value = new MediaSource()
    
    // 监听 sourceopen 事件
    mediaSource.value.addEventListener('sourceopen', handleSourceOpen)
    mediaSource.value.addEventListener('sourceended', () => {
      addLog('info', 'MediaSource 已结束')
    })
    mediaSource.value.addEventListener('sourceclose', () => {
      addLog('info', 'MediaSource 已关闭')
    })
    
    // 将 MediaSource 附加到 video 元素
    videoRef.value.src = URL.createObjectURL(mediaSource.value)
    
    addLog('success', 'MediaSource 创建成功')
    
  } catch (err) {
    console.error('加载视频失败:', err)
    addLog('error', `加载失败: ${err instanceof Error ? err.message : '未知错误'}`)
  } finally {
    isLoading.value = false
  }
}

// 处理 sourceopen 事件
const handleSourceOpen = () => {
  if (!mediaSource.value) return
  
  addLog('success', 'MediaSource 已打开')
  
  try {
    // 检查格式支持
    const mimeType = 'video/webm; codecs="vp8, vorbis"'
    
    if (!MediaSource.isTypeSupported(mimeType)) {
      addLog('error', `不支持的格式: ${mimeType}`)
      addLog('info', '尝试使用 MP4 格式...')
      
      const mp4Type = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
      if (!MediaSource.isTypeSupported(mp4Type)) {
        addLog('error', `也不支持 MP4 格式: ${mp4Type}`)
        return
      }
    }
    
    // 创建 SourceBuffer
    sourceBuffer.value = mediaSource.value.addSourceBuffer(mimeType)
    
    // 监听 SourceBuffer 事件
    sourceBuffer.value.addEventListener('updatestart', () => {
      addLog('info', 'SourceBuffer 开始更新')
    })
    
    sourceBuffer.value.addEventListener('updateend', () => {
      addLog('success', 'SourceBuffer 更新完成')
      updateBufferedRanges()
    })
    
    sourceBuffer.value.addEventListener('error', (e) => {
      addLog('error', 'SourceBuffer 错误')
      console.error('SourceBuffer error:', e)
    })
    
    addLog('success', 'SourceBuffer 创建成功')
    addLog('info', `使用格式: ${mimeType}`)
    
  } catch (err) {
    console.error('创建 SourceBuffer 失败:', err)
    addLog('error', `创建 SourceBuffer 失败: ${err instanceof Error ? err.message : '未知错误'}`)
  }
}

// 添加片段
const appendSegment = async () => {
  if (!sourceBuffer.value || sourceBuffer.value.updating) {
    addLog('warning', 'SourceBuffer 正在更新中，请稍后')
    return
  }
  
  isAppending.value = true
  
  try {
    // 生成模拟片段数据
    const segmentData = generateVideoSegment(segmentCount.value)
    
    // 添加到 SourceBuffer
    sourceBuffer.value.appendBuffer(segmentData)
    segmentCount.value++
    
    addLog('info', `添加片段 #${segmentCount.value}`)
    
  } catch (err) {
    console.error('添加片段失败:', err)
    addLog('error', `添加片段失败: ${err instanceof Error ? err.message : '未知错误'}`)
  } finally {
    isAppending.value = false
  }
}

// 清空缓冲区
const clearBuffer = async () => {
  if (!sourceBuffer.value || sourceBuffer.value.updating) return
  
  isClearing.value = true
  
  try {
    const buffered = sourceBuffer.value.buffered
    if (buffered.length > 0) {
      const start = buffered.start(0)
      const end = buffered.end(buffered.length - 1)
      
      sourceBuffer.value.remove(start, end)
      addLog('info', `清空缓冲区: ${start.toFixed(2)}s - ${end.toFixed(2)}s`)
      
      // 等待移除完成
      await new Promise<void>((resolve) => {
        const handler = () => {
          sourceBuffer.value?.removeEventListener('updateend', handler)
          resolve()
        }
        sourceBuffer.value?.addEventListener('updateend', handler)
      })
      
      addLog('success', '缓冲区已清空')
      updateBufferedRanges()
    }
    
  } catch (err) {
    console.error('清空缓冲区失败:', err)
    addLog('error', `清空失败: ${err instanceof Error ? err.message : '未知错误'}`)
  } finally {
    isClearing.value = false
  }
}

// 结束流
const endStream = () => {
  if (!mediaSource.value || mediaSource.value.readyState !== 'open') return
  
  try {
    mediaSource.value.endOfStream()
    addLog('success', '流已结束')
  } catch (err) {
    console.error('结束流失败:', err)
    addLog('error', `结束流失败: ${err instanceof Error ? err.message : '未知错误'}`)
  }
}

// 视频事件处理
const handleTimeUpdate = () => {
  if (videoRef.value) {
    currentTime.value = videoRef.value.currentTime
    duration.value = videoRef.value.duration || 0
    updateBufferedRanges()
  }
}

const handlePlay = () => {
  addLog('info', '视频开始播放')
}

const handlePause = () => {
  addLog('info', '视频已暂停')
}

// 清理
onUnmounted(() => {
  if (mediaSource.value) {
    if (mediaSource.value.readyState === 'open') {
      mediaSource.value.endOfStream()
    }
  }
  
  if (videoRef.value) {
    videoRef.value.src = ''
  }
})
</script>

